]> dgit.raspbian.org Git - ostree.git/commitdiff
checkout: Fix GVariant leak when scanning for opaque whiteouts
authorJonas Svatos <jonas.svatos@nfa.cz>
Thu, 11 Jun 2026 08:02:44 +0000 (10:02 +0200)
committerJonas Svatos <jonas.svatos@nfa.cz>
Thu, 11 Jun 2026 08:02:44 +0000 (10:02 +0200)
Breaking out of g_variant_iter_loop() leaves ownership of the current
element with the caller. The opaque-whiteout scan in
checkout_tree_at_recurse() breaks out of the loop when it finds a
match, and then cleared the local pointer, leaking one reference to
the extracted checksum variant on every directory that contains an
opaque whiteout entry.

A leaked child variant keeps the whole backing dirtree object alive,
including its GMappedFile when the object was large enough to be
mmap'd rather than read into the heap. In a process that unmounts the
target filesystem afterwards - notably `bootc install to-disk`, which
checks out container layers with process_whiteouts enabled and then
unmounts the physical root - the stale mapping makes the final
`umount -R` fail with EBUSY, aborting the installation.

Since the scan only needs the entry name, pass NULL to skip extracting
the checksum entirely, so nothing needs freeing on the early exit.

Fixes: https://github.com/bootc-dev/bootc/issues/2246
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Jonas Svatos <jonas.svatos@nfa.cz>
src/libostree/ostree-repo-checkout.c

index aa32ff4a85c349c5652009e429515841299e88b2..b2e68fdad54ffa51b810e6c7437b94ef69808dfb 100644 (file)
@@ -1031,15 +1031,19 @@ checkout_tree_at_recurse (OstreeRepo *self, OstreeRepoCheckoutAtOptions *options
       g_autoptr (GVariant) dir_file_contents = g_variant_get_child_value (dirtree, 0);
       GVariantIter viter;
       const char *fname;
-      g_autoptr (GVariant) contents_csum_v = NULL;
       g_variant_iter_init (&viter, dir_file_contents);
-      while (g_variant_iter_loop (&viter, "(&s@ay)", &fname, &contents_csum_v))
+      /* We only need the name; pass NULL to skip extracting the checksum.
+       * Note that breaking out of a g_variant_iter_loop() without freeing
+       * extracted values would leak them - and a leaked child variant pins
+       * the whole (possibly mmap'd) dirtree object in memory, which kept
+       * the filesystem busy across the final unmount in `bootc install`.
+       */
+      while (g_variant_iter_loop (&viter, "(&s@ay)", &fname, NULL))
         {
           is_opaque_whiteout = (g_str_equal (fname, OPAQUE_WHITEOUT_NAME));
           if (is_opaque_whiteout)
             break;
         }
-      contents_csum_v = NULL; /* iter_loop freed it */
     }
 
   /* First, make the directory.  Push a new scope in case we end up using